﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SuperKit
{
    /*
     * 这个项目的功能是将相似的文件合并到一个目录里面。
     * 比如说有如下文件：
     * 美女图片 Vol 1.pdf
     * 美女图片 Vol 2.pdf
     * 美女图片 Vol 3.pdf
     * 然后会把这三个具有一定名称相似度的项目，给他创建一个目录“美女图片 Vol”，然后把这三个文件放进去。
     */
    class SplitFileToDirectory : CommandExecutor {
        private class GroupItem {
            public FileInfo file;
            public int index;

            public GroupItem(FileInfo file, int index) {
                this.file = file;
                this.index = index;
            }
        }

        // 当为true的时候，即便这个项目只有他一个，也给他归到文档中。为false的时候跳过不处理
        private bool pickSingle;
        // 当为true的时候，表示一般这个项目之前是有一个作者或是制作公司的名称。用[公司]这样的东西放在前面，那么去掉这个Brand。
        private bool ignoreBrand;
        private FileInfo[] files;
        // 已经处理过的，用于比较的名称
        private string[] compareName;
        private bool[] processed;
        // 相似度，当两者的文件名相似到多少程序，判定为同类，一般为1半以上相似，就判断为一样。
        private float sameRate;
        List<GroupItem> groups = new List<GroupItem>();

        public SplitFileToDirectory(ArgReader arg, IExecutorOwner form, string fpath) : base(arg, form, fpath) {
            pickSingle = arg.IsContain("-pickSingle");
            ignoreBrand = arg.IsContain("-ignoreBrand");
            sameRate = arg.GetFloat("-sameRate", 0.50f);
        }

        public override void Execute() {
            base.Execute();

            DirectoryInfo dir = new DirectoryInfo(FilePath);
            files = dir.GetFiles();
            processed = new bool[files.Length];
            compareName = new string[files.Length];
            for (int i = 0; i < processed.Length; i++) {
                processed[i] = false;
                compareName[i] = RemoveRedundance(files[i].Name);
            }

            for (int i = 0; i < files.Length; i++) {
                if (processed[i] == false) {
                    Process(i, files[i]);
                }
            }

            End();
        }

        private void Process(int index, FileInfo file) {
            processed[index] = true; // 标记自身

            groups.Clear();
            groups.Add(new GroupItem(file, index)); // 自已总在里面

            string name = compareName[index];

            int minSameIndex = name.Length;

            for (int i = 0; i < processed.Length; i++) {
                if (processed[i]) { // 跳过已经处理的，和自已。
                    continue;
                }
                // 比较两个文件名，如果相似部分大于一半，则表示属于同种
                int sameIndex = GetSameIndex(name, compareName[i]);
                if (sameIndex > name.Length * sameRate) {
                    processed[i] = true;
                    groups.Add(new GroupItem(files[i], index));
                    minSameIndex = Math.Min(minSameIndex, sameIndex);
                }
            }

            // 当只有一个项目，而且不处理的时候，跳过
            if (groups.Count == 1 && pickSingle == false) {
                SetStatus($"跳过单个项目：{file.Name}");
                return;
            }

            // 为此项目增加目录
            string dirName = name.Substring(0, minSameIndex).Trim();
            string dir = Path.Combine(FilePath, dirName);
            if (Directory.Exists(dir) == false) {
                Directory.CreateDirectory(dir);
            }

            // 将文件移动到目录            
            foreach (var i in groups) {
                string path = Path.Combine(dir, i.file.Name);
                SetStatus($"移动:{i.file.Name}");
                File.Move(i.file.FullName, path);
            }
            
        }

        private string RemoveRedundance(string name) {
            name = Path.GetFileNameWithoutExtension(name);
            // 这个用于移除[100P]这样的标志图片数量的页码。
            name = Kit.ReplaceRegex(name, "\\[[0-9]+P\\]");
            // 这个用于移除[230131]这样的标记日期的信息(如果有[1]这样的序号，也一并移除了，因为会更方便）
            name = Kit.ReplaceRegex(name, "\\[[0-9]+\\]");

            if (ignoreBrand) {
                name = RemoveBrand(name);
            }

            return name.Trim();
        }

        private string RemoveBrand(string name) {
            int index = name.IndexOf(']');
            if (index == -1) {
                return name;
            }
            // 如果这个index后面没有文字了，表示这是仅有的名称，不是Brand，跳过。
            if (index + 3 >= name.Length) { // +3表示还剩下有3个文字之下，都视为Brand。
                return name;
            }
            return name.Substring(index + 1);
        }

        private int GetSameIndex(string a, string b) {
            a = Path.GetFileNameWithoutExtension(a);
            b = Path.GetFileNameWithoutExtension(b);
            

            int index = 0;
            for (int i = 0; i < a.Length; i++) {
                if (i >= b.Length) { // 另外一个已经走到最后了。
                    return index;
                }
                if (a[i] != b[i]) {
                    return index;
                }
                index++;
            }
            return index;
        }

    }
}
